<?php
/**
 * Created by PhpStorm.
 * User: qch
 * Date: 2015/5/24
 * Time: 6:40
 */

namespace J;


use J\Web\Context;

/**
 * 实现意图机制
 * [$module+$control+$action]
 *
 * @property-read String $pathinfo
 *
 * @property-read String $module
 * @property-read String $controller
 * @property-read String $action
 *
 * @property-read String $method
 *
 * @author qch
 */
class Intent
{
    const METHOD_FETCH   = 'FETCH';
    const KEY_ACTION     = 'action';
    const KEY_CONTROLLER = 'controller';
    const KEY_MODULE     = 'module';
    const KEY_METHOD     = 'method';
    const KEY_COMMAND    = 'command';

    /**
     * 自动填充，只读属性
     */
    use TReadOnly;
    use AutoSet;

    /**
     * @var  mixed  执行结果
     */
    public $value = null;

    /**
     * @var Context 上下文
     */
    protected $context;

    /**
     * 动作标识 能被Application解析到特定的模型
     * 前提：Module提前向Application注册
     * 优先级最高
     * @var string
     */
    protected $command;

    /**
     * @var bool 是否路由解析
     */
    protected $routed = false;

    protected $option = self::METHOD_FETCH;

    /**
     * @var Application
     */
    protected $app = null;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    /**
     * @return Application
     */
    public function getApp()
    {
        return $this->app;
    }

    /**
     * @return String
     */
    public function getCommand(): String
    {
        return $this->command;
    }

    /**
     * @return String
     */
    public function getOption()
    {
        return $this->option;
    }

    /**
     * 获取/创建 pathinfo
     * @param array $array
     * @return bool|string
     */
    public function getPathinfo($array = [])
    {
        if(!$this->routed) return false;

        if (is_string($array)) {
            $action = $array;
            $controller = $this->controller;
        } else {
            $action = array_isset($array, self::KEY_ACTION, $this->action);
            $controller = array_isset($array, self::KEY_CONTROLLER, $this->controller);
        }

        /*
         * 构建符合规则的URL
         */
        return $this->getApp()->Router()->getUrl([
            'module' => $this->module,
            'controller' => $controller,
            'action' => $action
        ]);

        // return $this->module.'/'.$controller.'/'.$action;
    }

    /**
     * @return Context
     */
    public function getContext()
    {
        return $this->context;
    }

    public function makeUrl($path = [], $file = null)
    {
        try {
            if (!$file) $file = $this->getContext()->getUrl()->getScriptUrl();
        } catch (\Exception $e) {
            $file = '';
        }

        return rtrim($file, '/') . '/' . ltrim($this->getPathinfo($path), '/');
    }

    /**
     * 权限路径
     * @return string
     */
    public function createAuthorityString()
    {
        return $this->module.'/'.$this->controller;
    }

    /**
     * 执行意图并返回结果
     *
     * @param string $command
     * @param mixed $properties
     * @return ReturnValue
     */
    public function fetch($command , $properties = null)
    {
        $this->command = $command;
        if(is_array($properties)) $this->property($properties);

        return $this->send();
    }

    /**
     * 意图内部直接跳转
     * @param string $command 目标意图Id
     *
     * @return Boolean
     */
    public function jump($command)
    {
        $this->command = $command;
        return $this->run();
    }

    /**
     * 执行意图并返回结果
     *     回调函数 function(Array $processor) : ReturnValue 对路由解析结果做特殊处理
     *
     *
     * @param \Closure $callback
     * @return ReturnValue
     */
    protected function send($callback = null)
    {
        $this->getApp()->debug(Message::INTENT_START, ['intent' => $this->command]);

        $return = $this->run($callback);

        $this->getApp()->debug(Message::INTENT_RECEIVED, ['intent' => $this->command]);

        return new ReturnValue($this->value, ($return !== false));
    }

    /**
     * 执行意图并返回结果
     *
     * @param \Closure $cb 回调函数 function(Array $processor) : ReturnValue 对路由解析结果做特殊处理
     *
     * @return bool|null
     */
    protected function run($cb = null)
    {
        $this->routed = false;

        return $this->app->invoke($this, function($processor) use ($cb) {
            $this->routed = true;
            $this->property($processor);
            if($cb) $cb($processor);
        });
    }

    /**
     * 请求意图处理
     *
     * @param Context $context
     * @return void
     */
    public function Request($context)
    {
        $path = $context->getPathinfo();

        // TODO 调用子域名处理程序
        // 处理自定义模块功能
        if(defined('__MODULE__') and !empty(__MODULE__)) $path = '/'.__MODULE__.$path;

        $this->command = $path;

        // 将解析结果绑定到$_GET
        $callback = function ($get){
            $_GET = array_merge($_GET, $get);
            $_REQUEST = array_merge($_REQUEST, $get);
        };
        $this->option = __OPTION__;

        $this->attributes[Intent::KEY_METHOD] = http_method();

        $this->context = $context;

        $context->response($this->send($callback));
    }

    /**
     * 返回Json数据
     * @param bool   $status
     * @param string $msg
     * @param array  $data
     */
    public function ajax($status, $msg = null, $data = [])
    {
        $this->value = value_ajax($status, $msg, $data);
    }

    /**
     * 自定义设置函数
     * @param $key
     * @param $value
     */
    protected function auto_set_attribute($key, $value)
    {
        $this->attributes[$key] = $value;
    }
}
